package com.firefly.codec.http2.hpack;

import java.nio.ByteBuffer;

public class NBitInteger {
    public static int octectsNeeded(int n, int i) {
        if (n == 8) {
            int nbits = 0xFF;
            i = i - nbits;
            if (i < 0)
                return 1;
            if (i == 0)
                return 2;
            int lz = Integer.numberOfLeadingZeros(i);
            int log = 32 - lz;
            return 1 + (log + 6) / 7;
        }

        int nbits = 0xFF >>> (8 - n);
        i = i - nbits;
        if (i < 0)
            return 0;
        if (i == 0)
            return 1;
        int lz = Integer.numberOfLeadingZeros(i);
        int log = 32 - lz;
        return (log + 6) / 7;
    }

    public static void encode(ByteBuffer buf, int n, int i) {
        if (n == 8) {
            if (i < 0xFF) {
                buf.put((byte) i);
            } else {
                buf.put((byte) 0xFF);

                int length = i - 0xFF;
                while (true) {
                    if ((length & ~0x7F) == 0) {
                        buf.put((byte) length);
                        return;
                    } else {
                        buf.put((byte) ((length & 0x7F) | 0x80));
                        length >>>= 7;
                    }
                }
            }
        } else {
            int p = buf.position() - 1;
            int bits = 0xFF >>> (8 - n);

            if (i < bits) {
                buf.put(p, (byte) ((buf.get(p) & ~bits) | i));
            } else {
                buf.put(p, (byte) (buf.get(p) | bits));

                int length = i - bits;
                while (true) {
                    if ((length & ~0x7F) == 0) {
                        buf.put((byte) length);
                        return;
                    } else {
                        buf.put((byte) ((length & 0x7F) | 0x80));
                        length >>>= 7;
                    }
                }
            }
        }
    }

    public static int decode(ByteBuffer buffer, int n) {
        if (n == 8) {
            int nbits = 0xFF;

            int i = buffer.get() & 0xff;

            if (i == nbits) {
                int m = 1;
                int b;
                do {
                    b = 0xff & buffer.get();
                    i = i + (b & 127) * m;
                    m = m * 128;
                } while ((b & 128) == 128);
            }
            return i;
        }

        int nbits = 0xFF >>> (8 - n);

        int i = buffer.get(buffer.position() - 1) & nbits;

        if (i == nbits) {
            int m = 1;
            int b;
            do {
                b = 0xff & buffer.get();
                i = i + (b & 127) * m;
                m = m * 128;
            } while ((b & 128) == 128);
        }
        return i;
    }
}
